package com.geekhalo.lego.plugin.lazyloader;

import com.geekhalo.lego.plugin.creator.JavaFileCreator;
import com.geekhalo.lego.plugin.support.ui.TableValue;
import com.geekhalo.lego.plugin.support.util.Utils;
import com.intellij.ide.util.ClassFilter;
import com.intellij.ide.util.TreeClassChooser;
import com.intellij.ide.util.TreeClassChooserFactory;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import java.awt.event.*;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CreateLazyLoaderDialog extends DialogWrapper {
    private JPanel contentPane;
    private JTextField lazyLoaderAnnName;
    private JTextField loaderName;
    private JButton selectLoaderType;
    private JTextArea showResult;
    private JTable methodsTable;
    private DefaultTableModel tableModel;
    private PsiMethod loaderMethod;
    private final Project project;
    private final Module module;
    private final String pkg;


    public CreateLazyLoaderDialog(Project project, Module module, String pkg) {
        super(project);
        this.project = project;
        this.module = module;
        this.pkg = pkg;

        setModal(true);

        // call onCancel() on ESCAPE
        contentPane.registerKeyboardAction(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                doCancelAction();
            }
        }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);

        initComponent();
        init();
    }

    private void initComponent() {
        // 选择 类型
        this.selectLoaderType.addActionListener(e->{
            TreeClassChooserFactory factory = TreeClassChooserFactory.getInstance(project);
            // 设置过滤条件，只选择 public 类型的类
            ClassFilter classFilter = psiClass -> psiClass.getModifierList().hasExplicitModifier(PsiModifier.PUBLIC);
            // 弹出选择类的窗口
            TreeClassChooser chooser = factory.createWithInnerClassesScopeChooser(
                    "选择加载器",
                    GlobalSearchScope.allScope(project),
                    classFilter,
                    null);
            chooser.showDialog();
            // 获取用户选择的类
            PsiClass selectedClass = chooser.getSelected();
            // 如果用户选择了类，则在控制台输出类名
            if (selectedClass != null) {
                updateMethods(selectedClass);
                loaderName.setText(selectedClass.getQualifiedName());
            }
        });

        this.tableModel = new DefaultTableModel(){
            @Override
            public boolean isCellEditable(int row, int column) {
                //all cells false
                return false;
            }
        };

        this.methodsTable.setModel(tableModel);
        this.tableModel.addColumn("可用方法");

        this.methodsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent event) {
                // 通过检查 ListSelectionEvent，可以确保只处理完成选择的事件，而不是每次用户点击表格就触发
                if (!event.getValueIsAdjusting()) {
                    // 获取选中行的索引
                    int selectedRow = methodsTable.getSelectedRow();

                    // 通过 DefaultTableModel，可以获取对应行的数据
                    Object data1 = methodsTable.getValueAt(selectedRow, 0); // 第一列的数据

                    // 现在你可以处理这些数据
                   updateCodeShow(((TableValue) data1).getMethod());
                }
            }
        });
    }

    private void updateCodeShow(PsiMethod method) {
        LazyLoaderTemplate.CreateLazyLoaderContext context = buildContext(method);

        String content = LazyLoaderTemplate.createShowView(context);
        this.showResult.setText(content);
        this.loaderMethod = method;
    }

    @NotNull
    private LazyLoaderTemplate.CreateLazyLoaderContext buildContext(PsiMethod method) {
        LazyLoaderTemplate.CreateLazyLoaderContext context = new LazyLoaderTemplate
                .CreateLazyLoaderContext(this.pkg, this.lazyLoaderAnnName.getText());

        context.setBeanName(Utils.getBeanName(this.loaderName.getText()));
        context.setLoadMethodName(method.getName());
        List<String> parameters = Stream.of(method.getParameterList().getParameters())
                .map(psiParameter -> psiParameter.getName())
                .collect(Collectors.toList());
        context.setParameters(parameters);
        return context;
    }

    private void updateMethods(PsiClass selectedClass) {
        methodsTable.clearSelection();
        tableModel.setRowCount(0);
        for (PsiMethod method : selectedClass.getAllMethods()) {
            if (accept(method)) {
                tableModel.addRow(new Object[]{new TableValue(selectedClass, method)});
            }
        }
    }

    private boolean accept(PsiMethod method) {
        return method.getReturnType() != null && !Utils.isObjectMethod(method);
    }

    @Override
    protected void doOKAction(){
        createFiles();
        super.doOKAction();
    }

    private void createFiles() {
        if (this.loaderMethod != null){
            LazyLoaderTemplate.CreateLazyLoaderContext context = this.buildContext(this.loaderMethod);
            String content = LazyLoaderTemplate.create(context);
            JavaFileCreator.createJavaFileInPackage(this.project,
                    this.module, pkg,
                    this.lazyLoaderAnnName.getText(),
                    content);
        }
    }

    @Override
    public void doCancelAction(){
        super.doCancelAction();
    }


    @Override
    protected @Nullable JComponent createCenterPanel() {
        return contentPane;
    }

}
